package net.e_agri.wap;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.e_agri.cache.ImageCacheEntry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;

@SuppressWarnings("serial")
public class ImageCacheServlet extends HttpServlet {

	private static final Log log = LogFactory.getLog(ImageCacheServlet.class);
	
	private static ImagesService imagesService = null;
	
	private static Objectify objectify = null;

	private static String selfRoot = "";

	public void init(){
		imagesService = ImagesServiceFactory.getImagesService();

		selfRoot = getServletContext().getInitParameter("SelfRoot");
		
		ObjectifyService.register(ImageCacheEntry.class);
		objectify = ObjectifyService.begin();
	}
	
	public void destroy(){
	}
	
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
		throws ServletException, IOException
	{
		printParameters(req);
		if(req.getParameter("files") == null)
			return;
		
		FileService fileService = FileServiceFactory.getFileService();
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		InputStream in = null;
		String blobImagePath = null;
		String blobKeyString = null;
		String filePath = null;
		
		ImageCacheEntry imgCache = null;

		for(String fileUrl : req.getParameter("files").split(",")){

			imgCache = objectify.query(ImageCacheEntry.class).filter("sourceUrl", fileUrl).get();
		    //if(objectify.query(ImageCacheEntry.class).filter("sourceUrl", fileUrl).count() > 0){
		    if(imgCache != null){
				log.debug("already Cached : " + fileUrl + " = " + imgCache.cacheUrl);
				resp.getWriter().write(imgCache.cacheUrl);
		    	continue;
		    }
		    AppEngineFile blobFile = fileService.createNewBlobFile("image/jpg");
		    FileWriteChannel writeChannel = fileService.openWriteChannel(blobFile, true);
		    
		    filePath = fileUrl;
		    if(filePath.indexOf("img.php?filename") != -1)
		    	filePath += "&h=120&w=120";

	        in = new URL(filePath).openStream();
	        byte[] buffer = new byte[1024];
	        for (int length = 0; (length = in.read(buffer)) > 0;)
	        	out.write(buffer, 0, length);

		    writeChannel.write(ByteBuffer.wrap(out.toByteArray()));
		    writeChannel.closeFinally();

		    BlobKey blobKey = fileService.getBlobKey(blobFile);
		    
		    String selfRootWithoutPort = selfRoot;
		    if(selfRoot.indexOf(":",5) != -1)
		    	selfRootWithoutPort = selfRoot.substring(0, selfRoot.lastIndexOf(":"));

			blobImagePath = imagesService.getServingUrl(blobKey);
			if(!blobImagePath.startsWith("http"))
				blobImagePath = selfRoot + blobImagePath;			
			if(blobImagePath.startsWith("http://0.0.0.0"))
				blobImagePath = blobImagePath.replace("http://0.0.0.0", selfRootWithoutPort);

			blobImagePath = blobImagePath.replace("//_ah", "/_ah");
			log.debug("received to BlobStore:" + blobImagePath);

			blobKeyString = blobKey.getKeyString();
			log.debug("blobKey:" + blobKeyString);

	  		log.info("cached:" + fileUrl + " = " + blobImagePath);
	  		objectify.put(new ImageCacheEntry(fileUrl, blobImagePath));

			resp.getWriter().write(blobImagePath);
		}
	}

	@SuppressWarnings("unchecked")
	private void printParameters(HttpServletRequest req){
		StringBuffer logBuf = new StringBuffer();
		for(String paramName : (Set<String>)req.getParameterMap().keySet())
			logBuf.append("\n\t").append(paramName).append(" = [")
				.append(req.getParameter(paramName)).append("]");
		log.debug(logBuf.toString());
	}
}
